//
// Created by root on 5/30/17.
//

#include "../basic/operator.h"

Cell* make_decimal(Scheme *sc, double num) {
    Cell* x = make_cell(sc, G_NIL, G_NIL);
    (x)->_type = DECIMAL_TYPE;
    (x)->_doubleValue = num;
    return (x);
}

int equals_double(double a, double b) {
    return ((a - b) < DECIMAL_MIN && (a - b) > -DECIMAL_MIN);
}

int is_zero_decimal(Cell* x) {
    return ((x->_doubleValue) < DECIMAL_MIN && (x->_doubleValue) > -DECIMAL_MIN);
}

Cell* decimal_add(Scheme *sc, Cell* x, Cell* y) {
    TYPE_CHECK_FOR_CELL(sc, x, DECIMAL_TYPE);
    TYPE_CHECK_FOR_CELL(sc, y, DECIMAL_TYPE);
    return make_decimal(sc, (x->_doubleValue) + (y->_doubleValue));
}

Cell* decimal_mul(Scheme *sc, Cell* x, Cell* y) {
    TYPE_CHECK_FOR_CELL(sc, x, DECIMAL_TYPE);
    TYPE_CHECK_FOR_CELL(sc, y, DECIMAL_TYPE);
    return make_decimal(sc, (x->_doubleValue) * (y->_doubleValue));
}

Cell* decimal_sub(Scheme *sc, Cell* x, Cell* y) {
    TYPE_CHECK_FOR_CELL(sc, x, DECIMAL_TYPE);
    TYPE_CHECK_FOR_CELL(sc, y, DECIMAL_TYPE);
    return make_decimal(sc, (x->_doubleValue) - (y->_doubleValue));
}

Cell* decimal_div(Scheme *sc, Cell* x, Cell* y) {
    TYPE_CHECK_FOR_CELL(sc, x, DECIMAL_TYPE);
    TYPE_CHECK_FOR_CELL(sc, y, DECIMAL_TYPE);
    if (is_zero_decimal(y)) {
        return make_default_exception(sc, "DIVISION_BY_ZERO", "/: division by zero.");
    }
    return make_decimal(sc, (x->_doubleValue) / (y->_doubleValue));
}

Cell* op_make_decimal(Scheme *sc) {
    Cell* x = first(sc->args);
    TYPE_CHECK(sc, x, DECIMAL_TYPE);
    return x;
}

void init_decimal_operators(Scheme *sc) {
    ADD_OPERATOR(sc, "make-decimal", make_decimal);
}
